/*
 * CS 567 GUI - Semester Project - "DecisionLists"
 * Jason Frank
 * Spring 2011
 *
 * This File:
 *
 */

package Decision_Lists;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.util.TreeMap;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

/*
 */
public class Panel_Fader {

  JPanel caller_panel, fadeout_panel, fadein_panel;
  boolean test_fade = false;
  Graphics g;  // the caller's Graphics obj
  ////////////////////////////////////////////
  ///// FADE MEMBERS /////////////////////////
  private final int fade_min_opacity = 0;
  private final int fade_max_opacity = 255;
  private float fade_alpha;  // used in paintComp (fade handlers set it as fadout_alpha or fadein_alpha)

  private int   fadeout_interval = 20;  // miliseconds between calls to the action listener.
  private int   fadeout_init_delay = 0;
  private Timer fadeout_timer = new Timer(fadeout_interval, null);  // handler func gets set in constructor
  private float fadeout_alpha = 1.0f;
  private float fadeout_delta = 0.04f;
   // For different type of alpha (0-255 for fg/bg Color obj))
  private int   fadeout_opacity = fade_max_opacity;  // to start with
  private int   fadeout_opacity_change = 10;

  private int   fadein_interval = fadeout_interval;  // miliseconds between calls to the action listener.
  private int   fadein_init_delay = fadeout_init_delay;
  private Timer fadein_timer = new Timer(fadein_interval, null);

  private float fadein_alpha = 0f;  // start opacity at 1.0 (fully opace)
  private float fadein_delta = 0.1f;
  // For different type of alpha (0-255 for fg/bg Color obj))
  private int   fadein_opacity = fade_min_opacity;
  private int   fadein_opacity_change = 10;

  JPanel newView;  // used in fade timers
  JPanel oldView;

  /////////// END OBJECT VARS ///////////////////
  ///////////////////////////////////////////////


  // Constructor
  public Panel_Fader(JPanel caller_panel,/* JPanel caller_super,*/ Graphics g, JPanel fadeout_panel, JPanel fadein_panel)  {

    this.caller_panel  = caller_panel;
    this.fadeout_panel = fadeout_panel;
    this.fadein_panel  = fadein_panel;
    this.g             = g;

    // Set the FADE EVENT HANDLERs
    fade_alpha = fadeout_alpha;  // initialize the generic alpha that paintComponent uses.
    fadeout_timer.addActionListener(fadeout_handler   );
    fadeout_timer.setInitialDelay(  fadeout_init_delay);
    fadein_timer.addActionListener( fadein_handler    );
    fadein_timer.setInitialDelay(   fadein_init_delay );

  } ////// end one constructor //////

 
  public void startFade() {

    // If this obj is for a "crossfade"
    if(fadeout_panel != null && fadein_panel != null ) {

      fadeout_timer.start();  // calls fadeout_handler() at specified intervals
    }
    // TODO: handle other cases
    else {
      System.err.println("Fading just 1 panel is not yet supported by Panel_Fader");
    }
  } ////// end startFade() ////////////////////

  
  // FADE OUT handler
  ActionListener fadeout_handler = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {

      fadeout_alpha -= fadeout_delta;
      // Stop the timer if the panel is fully faded out.
      if(fadeout_alpha < 0) {
        fadeout_alpha = 0;  // the AlphaComposite requires alpha to be [0.0,1.0]
        fade_alpha =  fadeout_alpha;  // set the generic alpha that paintComponent uses.
        fadeout_timer.stop();
        caller_panel.remove((Component)fadeout_panel);
            //current_center_view = (DL_ViewInterface) newView;
        caller_panel.add((Component)fadein_panel);
        fadein_timer.start();
      }///

      //////////////////////////////////////////
      //// GET THE ENTIRE VIEW RE-LAYED OUT ////
      caller_panel.invalidate();
      // Call pack() on the parent JFrame so that this panel will be re-layed out.
      JFrame frame = (JFrame) SwingUtilities.getRoot(caller_panel);
      frame.pack();


//      caller_panel.repaint();
      paint_caller_panel();
/*
      //////////////////////////////////////////
      //// GET THE ENTIRE VIEW RE-LAYED OUT ////
      caller_panel.invalidate();
      // Call pack() on the parent JFrame so that this panel will be re-layed out.
      JFrame frame = (JFrame) SwingUtilities.getRoot(caller_panel);
      frame.pack();
*/


      fade_alpha =  fadeout_alpha;  // set the generic alpha that paintComponent uses.
      if(test_fade) System.out.println("fadeout_handler just set fade_alpha to: " + fade_alpha);

      // <editor-fold defaultstate="collapsed" desc="Fading FG/BG way">
      /*
      fadeout_opacity -= fadeout_opacity_change;

      if (fadeout_opacity < fade_min_opacity) {
        fadeout_opacity = fade_min_opacity;
        fadeout_timer.stop();
        remove((Component) current_center_view);
        current_center_view = (DL_ViewInterface) newView;
        fadein_timer.start();
      }
      Color old_bg = oldView.getBackground();
      Color old_fg = oldView.getForeground();
      oldView.setBackground(new Color(old_bg.getRed(), old_bg.getGreen(), old_bg.getBlue(), fadeout_opacity));
      oldView.setForeground(new Color(old_fg.getRed(), old_fg.getGreen(), old_fg.getBlue(), fadeout_opacity));
      //oldView.setBackground(new Color(0, 0, 0, fade_max_opacity - fadeout_opacity));
      if (test_fade) {
        System.err.println("actionPerformed just set fadeout_opacity to: " + fadeout_opacity);

      }
      repaint(); */// </editor-fold>
    }
  }; ///// end FADE OUT handler ////

  // FADE IN handler
  ActionListener fadein_handler = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
      // <editor-fold defaultstate="collapsed" desc="Fading FG/BG way">
      /*
      // Add the new JPanel to this panel at the beginning of the is timer sequence
      if(fadein_opacity == fade_min_opacity) {
      add((Component)newView);
      }
      fadein_opacity += fadein_opacity_change;

      if(fadein_opacity > fade_max_opacity ) {
      fadein_opacity = fade_max_opacity;
      fadein_timer.stop();
      //finish_change_views();
      //TODO: finish this part?
      }
      Color new_bg = newView.getBackground();
      Color new_fg = newView.getForeground();
      newView.setBackground(new Color(new_bg.getRed(), new_bg.getGreen(), new_bg.getBlue(), fadein_opacity));
      newView.setForeground(new Color(new_fg.getRed(), new_fg.getGreen(), new_fg.getBlue(), fadein_opacity));

      if(test_fade) System.err.println("actionPerformed just set fadein_opacity to: " + fadein_opacity);
      repaint();
       */// </editor-fold>

      fadein_alpha += fadein_delta;
      // Stop the timer if the panel is fully faded out.
      if(fadein_alpha > 1.0 ) {
        fadein_alpha = 1.0f;  // the AlphaComposite requires alpha to be [0.0,1.0]
        fade_alpha =  fadein_alpha;  // set the generic alpha that paintComponent uses.
        fadein_timer.stop();
      }///
      caller_panel.repaint();
      //paint_caller_panel();

      fade_alpha =  fadein_alpha;  // set the generic alpha that paintComponent uses.
      if(test_fade) System.out.println("fadein_handler just set fade_alpha to: " + fade_alpha);

      reset_alphas();
    } /////////// end actionPerformed() (for the fadein_handler) //////
  };

  
  // emulating paintComponent in the calling panel (uses the panel's graphics obj)
  public void paint_caller_panel() {

    //(caller_panel.super).paintComponent(g);
    //caller_panel.repaint();  // trying to get it's super.paintComponent() called
    //((CenterPanel)caller_panel).call_super_paintComponent();

    // Save orig graphics before modifying it
    Graphics myG = g.create();
            //    Graphics2D g2 = (Graphics2D) myG; // 2D needed for composite information
    // MUST USE THE ORIGINAL G to make the fade work!
    Graphics2D g2 = (Graphics2D) g; // 2D needed for composite information
    /////////////////////////////////////////////////////////////////////////
    ///// SETUP "COMPOSITE" TO ENABLE ALPHA FADING (by timer & handler) /////

    // tutorial at http://java.sun.com/products/jfc/tsc/articles/swing2d/
    // Save orig composite - DO NOT RESTORE THE OLD COMPOSITE (to make the fade work!)
    Composite oldComposite = g2.getComposite();
    // Create an AlphaComposite
    Composite fadeout_composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, fade_alpha);
    // Set the composite on the Graphics2D object.
    g2.setComposite(fadeout_composite);

    if(test_fade) System.err.println("paintComponent just did setComposit() with fade_alpha: " + fade_alpha);

    g2.setPaint(caller_panel.getBackground()); // draw on top with same color as background
    g2.fillRect(0, 0, caller_panel.getWidth(), caller_panel.getHeight());

            // Restore the orig composite? - DO NOT RESTORE THE OLD COMPOSITE (to make the fade work!)
            //    g2.setComposite(oldComposite);  // DO NOT RESTORE THE OLD COMPOSITE (to make the fade work!)

    myG.dispose();
  } //// end paint_caller_panel() ///////

  private void reset_alphas() {
      // Resets
    fadein_opacity = fade_min_opacity;
    fadeout_opacity = fade_max_opacity;
    fadein_alpha = 0.0f;
    fadeout_alpha = 1.0f;
  }


} //////////////////// end class Panel_Fader /////////////////////////////
